package com.qcsec.config;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.qcsec.common.base.JacksonModule;
import com.qcsec.common.consts.CommonCst;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.time.ZoneId;
import java.util.Locale;
import java.util.TimeZone;

/**
 * @author admin
 * proxyBeanMethods=true:
 *  则表示被@Bean标识的方法都会被CGLIB进行代理，
 *  而且会走bean的生命周期中的一些行为（比如：@PostConstruct,@Destroy等 spring中提供的生命周期）,
 *  如果bean是单例的，那么在同一个configuration中调用
 *  即@Bean标识的方法，无论调用几次得到的都是同一个bean，就是说这个bean只初始化一次。
 * proxyBeanMethods=false:
 *  不会被拦截进行CGLIB代理，
 *  也就不会走bean的生命周期中的一些行为（比如：@PostConstruct,@Destroy等 spring中提供的生命周期），
 *  如果同一个configuration中调用@Bean标识的方法，就只是普通方法的执行而已，并不会从容器中获取对象。
 *  所以如果单独调用@Bean标识的方法就是普通的方法调用，而且不走bean的生命周期.
 *  如果配置类中的@Bean标识的方法之间不存在依赖调用的话，可以设置为false，可以避免拦截方法进行代理操作，也是提升性能的一种优化。
 *  但是需要注意，@Bean标识的返回值对象还是会放入到容器中的，从容器中获取bean还是可以是单例的，会走生命周期。
 *
 */
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(ObjectMapper.class)
@AutoConfigureBefore(JacksonAutoConfiguration.class)
public class JacksonConfig {
    @Bean
    @ConditionalOnMissingBean(Jackson2ObjectMapperBuilderCustomizer.class)
    public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
        SimpleModule LongModule = new SimpleModule();
        LongModule.addSerializer(Long.class, ToStringSerializer.instance);
        return builder -> builder
                .locale(Locale.CHINA)
                .timeZone(TimeZone.getTimeZone(ZoneId.systemDefault()))
                //针对于Date类型，文本格式化
                .simpleDateFormat(CommonCst.DATE_TIME_PATTERN)
                //若POJO对象的属性值为null，序列化时不进行显示
                .serializationInclusion(JsonInclude.Include.NON_NULL)
                //若POJO对象的属性值为""，序列化时不进行显示
                .serializationInclusion(JsonInclude.Include.NON_EMPTY)
                //DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES相当于配置，JSON串含有未知字段时，反序列化依旧可以成功
                .failOnUnknownProperties(false)
                //序列化时的命名策略——驼峰命名法
//                    .propertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE)
                //默认关闭，将char[]数组序列化为String类型。若开启后序列化为JSON数组。
                .featuresToEnable(SerializationFeature.WRITE_CHAR_ARRAYS_AS_JSON_ARRAYS)
                //默认开启：如果一个类没有public的方法或属性时，会导致序列化失败。关闭后，会得到一个空JSON串。
                .featuresToDisable(SerializationFeature.FAIL_ON_EMPTY_BEANS)
                .modules(JacksonModule.simpleModule(), JacksonModule.javaTimeModule());
    }
}
